﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MultiViewer.Network;
using System.Threading;
using MultiViewer.Display;
using System.Diagnostics;
using MouseSpace;
using MultiViewer.Display.TiledImages;
using MouseKeyboardLibrary;

namespace MultiViewer.Client
{
    /// <summary>Main window for MultiViewer.Client</summary>
    public partial class MainWindow : MultiViewerWindow
    {
        private MouseWindow window;
        public MouseWindow Window
        {
            get { return this.window; }
            set { this.window = value; }
        }
        private bool cursor;
        public bool MousePressOn
        {
            get { return this.cursor; }
            set { this.cursor = value; }
        }
        private TraceViewer traceViewer;
        private D3VirtualEarthViewer imageViewer;

        public MainWindow()
        {
            InitializeComponent();
            window = new MouseWindow();
            window.Visibility = Visibility.Hidden;
            traceViewer = new TraceViewer();
            Content = traceViewer;
#if DEBUG
            Trace.Listeners.Add(traceViewer.Listener);
#else
            Debug.Listeners.Add(traceViewer.Listener);
#endif
            Trace.WriteLine("MultiViewer.Client is starting...");
            Debug.WriteLine("MultiViewer is built in Debug mode");

            ThreadPool.SetMaxThreads(32, 32);
        }

        protected override void OnClosed(EventArgs e)
        {
            if (Node != null)
            {
                if (Content is TiledImageViewer)
                    ((TiledImageViewer)Content).DetachNode();
                Node.Stop();
            }
            window.Close();
            base.OnClosed(e);
        }

        protected override void OnNodeConnected()
        {
            base.OnNodeConnected();
            Node.AddMessageHandler<ShutdownRequest>(Dispatcher,ShutdownHandler);
            Node.AddNotificationHandler<MouseNotification>(MouseNotificationHandler);
            Node.AddNotificationHandler<MouseClickNotification>(MouseClickNotificationHandler);
            Node.AddNotificationHandler<MouseWheelNotification>(Dispatcher, MouseWheelNotificationHandler);
        }

        private void BeginInvoke<T>(NotificationHandler<T> handler, T argument)
        {
            Dispatcher.BeginInvoke(new SyncInvoker(delegate()
            {
                try
                {
                    handler(argument);
                }
                catch (Exception exc)
                {
                    Trace.WriteLine("Exception in " + typeof(T).Name + " handler: " + exc.Message);
                }
            }));
        }

        protected override void InitDisplayHandler(InitDisplayRequest request, HandlerResult<object> result)
        {
            base.InitDisplayHandler(request, null);
            if (request.Fullscreen)
            {
                WindowStyle = WindowStyle.None;
                WindowState = WindowState.Maximized;
                Topmost = true;
            }
            else
            {
                // TODO: Transform from pixels to WPF units
                Width = request.Width;
                Height = request.Height;
            } 
            window.Width = request.CursorWidth;
            window.Height = request.CursorHeight;
            MousePressOn = request.SimulateMouseEvents;
            imageViewer = new D3VirtualEarthViewer();
            Content = imageViewer;
            imageViewer.AttachNode(Node);
            result.SetSuccess(true);
        }

        private void ShutdownHandler(ShutdownRequest request, HandlerResult<object> result)
        {
            Close();
            result.SetSuccess(true);
        }

        private void MouseNotificationAsyncHandler(MouseNotification e)
        {
            BeginInvoke(MouseNotificationHandler, e);
        }

        private void MouseNotificationHandler(MouseNotification e)
        {
            try
            {
                // TODO: handle mouse events properly
                if (!window.Dispatcher.CheckAccess())
                {
                    this.Dispatcher.Invoke(
                      System.Windows.Threading.DispatcherPriority.Normal,
                      new Action(
                        delegate()
                        {
                            if (e.X != -10000)
                            {
                                if(this.MousePressOn) MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                if (this.MousePressOn) MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                window.Visibility = Visibility.Visible;
                                window.Left = e.X + this.Left;
                                window.Top = e.Y + this.Top;
                                window.Topmost = true;
                                window.Focus();
                                window.Show();
                            }
                            else
                            {
                                if (window != null) window.Visibility = Visibility.Hidden;
                            }
                        }
                    ));
                }
                else
                {
                    if (e.X != -10000)
                    {
                        window.Visibility = Visibility.Visible;
                        window.Left = e.X + this.Left;
                        window.Top = e.Y + this.Top;
                        window.Show();
                    }
                    else
                    {
                        if (window != null) window.Visibility = Visibility.Hidden;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void MouseCLickNotificationAsyncHandler(MouseClickNotification e)
        {
            BeginInvoke(MouseClickNotificationHandler, e);
        }

        private void MouseWheelNotificationHandler(MouseWheelNotification e)
        {
            MouseKeyboardLibrary.MouseSimulator.MouseWheel(e.Delta);
        }

        private void MouseClickNotificationHandler(MouseClickNotification e)
        {
            try
            {
                if (!this.Dispatcher.CheckAccess())
                {
                    window.Dispatcher.Invoke(
                      System.Windows.Threading.DispatcherPriority.Normal,
                      new Action(
                        delegate()
                        {
                            if (e.Button == MultiViewer.Display.MouseButton.LeftDown)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Left);
                            }
                            else if (e.Button == MultiViewer.Display.MouseButton.LeftUp)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Left);
                            }
                            else if (e.Button == MultiViewer.Display.MouseButton.RightDown)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Right);
                            }
                            else if (e.Button == MultiViewer.Display.MouseButton.RightUp)
                            {
                                MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                                MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                                MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Right);
                            }
                        }
                                ));
                }
                else
                {
                    if (e.Button == MultiViewer.Display.MouseButton.LeftDown)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Left);
                    }
                    else if (e.Button == MultiViewer.Display.MouseButton.LeftUp)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Left);
                    }
                    else if (e.Button == MultiViewer.Display.MouseButton.RightDown)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseDown(MouseKeyboardLibrary.MouseButton.Right);
                    }
                    else if (e.Button == MultiViewer.Display.MouseButton.RightUp)
                    {
                        MouseKeyboardLibrary.MouseSimulator.X = (int)(e.X + this.Left);
                        MouseKeyboardLibrary.MouseSimulator.Y = (int)(e.Y + this.Top);
                        MouseKeyboardLibrary.MouseSimulator.MouseUp(MouseKeyboardLibrary.MouseButton.Right);
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }    
}
